﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ProgNetAppBlocks.Base;
using ProgNetComponents;
using System.Drawing.Design;
using ProgNetComponents.Design.Editors;
using ProgNetDxComponents.Design.Editors;
using ProgNetComponents.Data.Query;
using ProgNetComponents.Design.TypeDescriptors;
using ProgNetDxComponents.ExtenderProviders.Browsers;
using ProgNetDxComponents.ExtenderProviders.Language;
using ProgNetComponents.Data;

namespace ProgNetAppBlocks.Forms
{
    [ProgNetComponents.Design.Attributes.AbstractClassReference(typeof(InternalProgNetQueryForm))]
    [TypeDescriptionProvider(typeof(AbstractClassTypeDescriptionProvider))]
    public abstract partial class ProgNetQueryForm : ProgNetForm
    {
        #region fields
        protected object CurrentRecordId;
        private SelectData _SelectData;
        protected SelectData SelectData
        {
            get
            {
                if (_SelectData == null && this.IsAppRunning())
                    _SelectData = SelectDataCache.GetData(SelectDataName);
                return _SelectData;
            }
        }
        protected Browser Browser
        {
            get
            {
                return BrowserCache.GetBrowser(BrowserName, false);
            }
        }

        protected virtual string ValueColumn
        {
            get { return Browser.ValueMember; }
        }
        protected virtual string DisplayColumn
        {
            get { return Browser.DisplayMember; }
        }
        protected virtual string FormText
        {
            get { return ProgNetLanguage.sGetStringDefault(BrowserName, BrowserName); }
        }
        #endregion

        #region Properties
        [Category(Categories.ProgNetSettings)]
        public DataSet DataSource
        {
            get;
            set;
        }

        [Category(Categories.ProgNetSettings),
        Editor(typeof(SelectDataNameEditor), typeof(UITypeEditor))]
        public string SelectDataName
        {
            get;
            set;
        }

        [Category(Categories.ProgNetSettings),
        Editor(typeof(BrowserNameEditor), typeof(UITypeEditor))]
        public string BrowserName
        {
            get;
            set;
        }

        [Category(Categories.ProgNetSettings)]
        public bool OpenRecordAfterSave
        {
            get;
            set;
        }

        [Category(Categories.ProgNetSettings)]
        public bool OpenOnLoad
        {
            get;
            set;
        }

        [Category(Categories.ProgNetSettings)]
        public bool AllowChangeText
        {
            get;
            set;
        }

        [Category(Categories.ProgNetSettings)]
        public string NewRecordText
        {
            get;
            set;
        }

        #endregion

        #region Ctor
        public ProgNetQueryForm(object id = null)
        {
            InitializeComponent();
            CurrentRecordId = id;
            OpenOnLoad = true;
        }

        #endregion

        public bool DoOpenRecord(object record)
        {
            CurrentRecordId = record;
            bool result = false;
            if (record.IsNull())
            {
                result = NewRecord();
                modeProvider1.CurrentMode = ProgNetDxComponents.ExtenderProviders.FormMode.New;
            }
            else
                result = OpenRecord(record);

            if (!result)
                modeProvider1.CurrentMode = ProgNetDxComponents.ExtenderProviders.FormMode.View;
            else
                DataSource.Tables[SelectData.SingleRecordQueries[0].TableDataSetName].Rows[0].BeginEdit();

            changeDetercorProvider1.ResetAll();
            SetFormText();
            return result;
        }

        protected virtual void FinishEdit()
        {
            this.FinishEditBindings();
        }

        protected virtual bool OpenRecord(object record)
        {
            bool result = false;
            result = Manager.FillDataSet(DataSource, new ObjectKeyValuePair(ValueColumn, record));
            if (!result)
                Manager.LastException.Log(this.GetType().FullName + ".OpenRecord(" + record + ")");
            return result;
        }
        protected virtual bool NewRecord()
        {
            DataSource.Clear();
            DataRow r = DataSource.Tables[SelectData.SingleRecordQueries[0].TableDataSetName].NewRow();
            DataSource.Tables[SelectData.SingleRecordQueries[0].TableDataSetName].Rows.Add(r);
            return true;
        }

        protected virtual bool SaveRecord()
        {
            bool result = false;
            result = SelectData.Manager.UpdateDataSet(DataSource);
            if (!result)
                SelectData.Manager.LastException.Log(this.GetType().FullName + ".SaveRecord()");
            return result;
        }
        protected abstract bool ValidateAll();
        protected virtual bool DeleteRecord()
        {
            bool result = false;
            result = SelectData.Manager.ExecuteNonQuery("DELETE FROM " + SelectData.SingleRecordQueries[0].TableName + " WHERE " +
                Browser.ValueMember + " = " + CurrentRecordId.AsString().EscapeSql()) > 0;
            if (!result)
                SelectData.Manager.LastException.Log(this.GetType().FullName + ".DeleteRecord()");
            return result;
        }

        protected virtual bool DoSaveRecord(bool forceOpen)
        {
            bool result = false;
            if (ValidateAll())
            {
                DataSource.Tables[SelectData.SingleRecordQueries[0].TableDataSetName].Rows[0].EndEdit();
                if (SaveRecord())
                {
                    if (forceOpen)
                    {
                        if (DoOpenRecord(CurrentRecordId))
                            result = true;
                    }
                    else
                    {
                        result = true;
                        changeDetercorProvider1.ResetAll();
                        SetFormText();
                    }
                }
                else
                {
                    DataSource.Tables[SelectData.SingleRecordQueries[0].TableDataSetName].Rows[0].BeginEdit();
                    this.ShowDxErrorDialog("Błąd zapisu rekordu!");
                    SelectData.Manager.LastException.Log();
                    result = false;
                }
            }
            else
            {
                this.ShowDxInfoDialog("Nie wszystkie wartości są poprawne.");
                result = false;
            }
            return result;
        }

        protected virtual void ToggleEdit(bool openRecord)
        {
            if (modeProvider1.CurrentMode == ProgNetDxComponents.ExtenderProviders.FormMode.Read)
                modeProvider1.CurrentMode = ProgNetDxComponents.ExtenderProviders.FormMode.Edit;
            else
            {
                bool toggle = false;
                FinishEdit();

                if (changeDetercorProvider1.HasChanges)
                {
                    DialogResult dlg = this.ShowDxYNCQuestionDialog("Zapisać zmiany?");
                    if (dlg == System.Windows.Forms.DialogResult.Yes)
                    {
                        toggle = DoSaveRecord(openRecord);
                    }
                    if (dlg == System.Windows.Forms.DialogResult.No)
                    {
                        if (DoOpenRecord(CurrentRecordId))
                            toggle = true;
                    }
                }
                if (toggle)
                    modeProvider1.CurrentMode = ProgNetDxComponents.ExtenderProviders.FormMode.Read;
            }
        }

        protected virtual void SetFormText()
        {
            if (CurrentRecordId.IsNull())
            {
                this.Text = NewRecordText;
            }
            else
            {
                if (BrowserName.IsNotNull())
                {
                    this.Text = FormText + " [ " + DataSource.Tables[SelectData.SingleRecordQueries[0].TableDataSetName].Rows[0][DisplayColumn].AsString() + " ] ";
                }
            }
        }

        #region Menu Click
        private void bbiOtworz_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            if (BrowserName.IsNotNull())
            {
                ObjectDialogResult dlg = BrowserCache.GetBrowser(BrowserName).ShowDialog();
                if (dlg.DialogResult == System.Windows.Forms.DialogResult.OK && dlg.Value.IsNotNull())
                {
                    DoOpenRecord(dlg.Value);
                }
            }
        }

        private void bbiOdswiez_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            if (modeProvider1.CurrentMode == ProgNetDxComponents.ExtenderProviders.FormMode.Read)
                DoOpenRecord(CurrentRecordId);
            else
                ToggleEdit(true);
            SetMenu();
        }

        private void bbiEdytuj_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            ToggleEdit(OpenRecordAfterSave);
            SetMenu();
        }

        private void bbiZapisz_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            FinishEdit();
            if (DoSaveRecord(OpenRecordAfterSave))
                modeProvider1.CurrentMode = ProgNetDxComponents.ExtenderProviders.FormMode.Read;
            SetMenu();
        }

        private void bbiUsun_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            if (DeleteRecord())
            {
                object id = BrowserCache.GetFirstId(BrowserName);
                if (id.IsNotNull())
                    DoOpenRecord(id);
                else
                    modeProvider1.CurrentMode = ProgNetDxComponents.ExtenderProviders.FormMode.Custom1;
            }
            SetMenu();
        }

        private void bbiDodaj_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            bool toggle = false;
            if (changeDetercorProvider1.HasChanges)
            {
                DialogResult dlg = this.ShowDxYNCQuestionDialog("Zapisać zmiany?");
                if (dlg == System.Windows.Forms.DialogResult.Yes)
                {
                    toggle = DoSaveRecord(false);
                }
                if (dlg == System.Windows.Forms.DialogResult.No)
                {
                    //if (DoOpenRecord(CurrentRecordId))
                    toggle = true;
                }
                if (dlg == System.Windows.Forms.DialogResult.Cancel)
                    toggle = false;
            }
            else
                toggle = true;
            if (toggle)
                DoOpenRecord(null);
        }

        private void bbiPierwszy_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            object id  = BrowserCache.GetFirstId(BrowserName);
            if (id.IsNotNull())
                DoOpenRecord(id);
            SetMenu();
        }

        private void bbiNastepny_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            object id  = BrowserCache.GetNextId(BrowserName, CurrentRecordId);
            if (id.IsNotNull())
                DoOpenRecord(id);
            SetMenu();
        }

        private void bbiPoprzedni_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            object id  = BrowserCache.GetPrevId(BrowserName, CurrentRecordId);
            if (id.IsNotNull())
                DoOpenRecord(id);
            SetMenu();
        }

        private void bbiOstatni_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e)
        {
            object id  = BrowserCache.GetLastId(BrowserName);
            if (id.IsNotNull())
                DoOpenRecord(id);
            SetMenu();
        }

        #endregion

        #region On Load
        private void ProgNetQueryForm_Load(object sender, EventArgs e)
        {
            if (this.IsAppRunning())
            {
                if (!this.SelectData.Manager.HasData)
                    this.SelectData.Manager.AddSelectData(this.DataSource, this.SelectData, true);

                PreInitForm();
                if (OpenOnLoad)
                {
                    DoOpenRecord(CurrentRecordId);
                }

                SetMenu();
            }
        }
        #endregion

        protected virtual void SetMenu()
        {
            modeProvider1.RefreshObjects(bbiPoprzedni, bbiPierwszy, bbiOstatni, bbiNastepny);
        }

        protected virtual void PreInitForm()
        {
            if (BrowserName.IsNull())
                bbiOtworz.Visibility = DevExpress.XtraBars.BarItemVisibility.Never;
            else
                bbiOtworz.Visibility = DevExpress.XtraBars.BarItemVisibility.Always;

            bbiNastepny.Visibility = bbiOstatni.Visibility = bbiPoprzedni.Visibility = bbiPierwszy.Visibility = bbiOtworz.Visibility;
        }

        protected virtual void ModeSettings_CustomGetControlModes(object sender, ProgNetDxComponents.ExtenderProviders.Settings.ModeSettingsEventArgs e)
        {
            if (this.IsAppRunning())
            {
                if (sender == bbiNastepny)
                    e.IsReadOnly |= BrowserCache.GetNextId(BrowserName, CurrentRecordId) == null;
                if (sender == bbiOstatni)
                    e.IsReadOnly |= BrowserCache.GetLastId(BrowserName) == null;
                if (sender == bbiPierwszy)
                    e.IsReadOnly |= BrowserCache.GetFirstId(BrowserName) == null;
                if (sender == bbiPoprzedni)
                    e.IsReadOnly |= BrowserCache.GetPrevId(BrowserName, CurrentRecordId) == null;
                if (sender == bbiZapisz)
                    e.IsReadOnly = !changeDetercorProvider1.HasChanges;
            }
        }

        protected virtual void ToggleName()
        {
            if (AllowChangeText)
            {
                if (changeDetercorProvider1.HasChanges)
                {
                    if (!this.Text.EndsWith(" *"))
                    {
                        this.Text += " *";
                    }
                }
                else
                {
                    if (this.Text.EndsWith(" *"))
                    {
                        this.Text.XReplace(" \\*$", "");
                    }
                }
            }
        }

        protected virtual void changeDetercorProvider1_ContextChanged(object sender, EventArgs e)
        {
            if (this.IsAppRunning())
            {
                modeProvider1.RefreshObjects(bbiZapisz);
                ToggleName();
            }
        }
    }

    public class InternalProgNetQueryForm : ProgNetQueryForm
    {

        protected override bool ValidateAll()
        {
            throw new NotImplementedException();
        }
    }
}
